﻿using System;
using System.Collections.Generic;
using System.Linq;
#if ODIN_INSPECTOR
using Sirenix.OdinInspector;
#endif
using UnityEngine;
using UnityEngine.Profiling;

namespace JH
{
    /// <summary>
    ///  图表的基本实现类
    /// </summary>
    /// <typeparam name="TPoint">数据点类型</typeparam>
    public abstract class BasicChart<TPoint> : BasicMono<TPoint>, IChart<TPoint>
        where TPoint : struct
    {
        /// <summary>
        ///  编辑器下的数据点列表
        /// </summary>
#if ODIN_INSPECTOR
        [LabelText("编辑器数据")]
#endif
        [SerializeField]
        protected List<TPoint> editorPoint;

        /// <summary>
        ///  图表的渲染器列表
        /// </summary>
        private IChartRender[] _renders;

        /// <summary>
        ///  图表的渲染器列表
        /// </summary>
        public IChartRender[] Renders
        {
            get
            {
                // 如果渲染器列表已经被缓存，则直接返回
                if (_renders != null) return _renders;

                // 如果渲染器列表为空，则获取所有子组件
                _renders ??= this.GetChartComps<IChartRender, TPoint>();

                //按照优先级排序
                if (_renders.Length > 1)
                    Array.Sort(_renders, Comparison);

                return _renders;
            }
        }

        /// <summary>
        ///  按照优先级对处理器进行排序后的集合
        /// </summary>
        private IProcessor<TPoint>[] _sortedProcessors;

        /// <summary>
        ///  数据处理器列表
        /// </summary>
        public IProcessor<TPoint>[] Processors =>
            _sortedProcessors ??= GetComponentsInChildren<IProcessor<TPoint>>()
                .OrderBy(i => i.Priority).ToArray();

        /// <summary>
        ///  全部的数据点集合
        /// </summary>
        protected abstract ICollection<TPoint> DataList { get; }

        /// <summary>
        ///  数据点集合
        /// </summary>
        public IReadOnlyList<TPoint> Data
        {
            get
            {
                if (DataList is IReadOnlyList<TPoint> ret)
                {
                    return ret;
                }

                throw new InvalidOperationException($"无法将类型{typeof(ICollection<TPoint>).Name}" +
                                                    $"转换为{typeof(IReadOnlyList<TPoint>).Name}，请自行实现接口IChartData<TPoint>");
            }
        }

        /// <summary>
        ///  获取指定类型的处理器
        /// </summary>
        /// <typeparam name="TProcessor">指定数据处理器类型</typeparam>
        public TProcessor GetProcessor<TProcessor>() where TProcessor : class, IProcessor<TPoint>
        {
            foreach (var processor in Processors)
            {
                if (processor is TProcessor ret)
                    return ret;
            }

            return null;
        }

        /// <summary>
        ///  添加数据点到图表数据中，并且可以选择是否进行处理和刷新
        /// </summary>
        private void AddPoint(TPoint point, bool processAndResRefresh)
        {
            if (DataList == null) return;
            DataList.Add(point);

            if (!processAndResRefresh) return;
            Refresh();
        }

        /// <summary>
        ///  添加数据点到图表数据中
        /// </summary>
        public void AddPoint(TPoint point)
        {
            AddPoint(point, true);
        }

        /// <summary>
        ///  添加多个数据点到图表数据中
        /// </summary>
        public void AddPoints(IEnumerable<TPoint> points)
        {
            if (points == null) return;

            // 如果是IList<TPoint>，则直接遍历
            if (points is IList<TPoint> list)
            {
                for (int i = 0; i < list.Count; i++)
                {
                    var point = list[i];
                    AddPoint(point, false);
                }

                Refresh();
                return;
            }

            // 调用迭代器
            foreach (var point in points) AddPoint(point, false);
            Refresh();
        }

        /// <summary>
        ///  添加多个数据点到图表数据中
        /// </summary>
        public void AddPoints(TPoint[] points)
        {
            if (points == null) return;
            for (int i = 0; i < points.Length; i++)
            {
                var point = points[i];
                AddPoint(point, false);
            }

            Refresh();
        }

        /// <summary>
        ///  从图表数据中移除数据点，并且可以选择是否进行处理和刷新
        /// </summary>
        private bool RemovePoint(TPoint point, bool processAndResRefresh)
        {
            if (DataList == null) return false;
            var success = DataList.Remove(point);
            if (!success) return false;
            if (!processAndResRefresh) return true;
            Refresh();
            return true;
        }

        /// <summary>
        ///  从图表数据中移除数据点
        /// </summary>
        public void RemovePoint(TPoint point)
        {
            RemovePoint(point, true);
        }

        /// <summary>
        ///  从图表数据中移除多个数据点
        /// </summary>
        public void RemovePoints(IEnumerable<TPoint> points)
        {
            if (points == null) return;
            bool anySuccess = false;
            foreach (var point in points)
            {
                if (!RemovePoint(point, false)) continue;
                if (!anySuccess) anySuccess = true;
            }

            if (anySuccess) Refresh();
        }

        /// <summary>
        ///  根据条件移除数据点
        /// </summary>
        public void RemovePoints(Predicate<TPoint> predicate)
        {
            if (DataList == null || predicate == null) return;
            bool anySuccess = false;
            foreach (var each in DataList)
            {
                if (predicate(each))
                {
                    if (!RemovePoint(each, false)) continue;
                    if (!anySuccess) anySuccess = true;
                }
            }

            if (anySuccess) Refresh();
        }

        /// <summary>
        ///  清空图表数据
        /// </summary>
        public void Clear()
        {
            if (DataList == null) return;

            // 清空数据列表
            DataList.Clear();

            // 清空数据后，刷新图表
            Refresh();
        }

        /// <summary>
        ///  可以通过此函数刷新图表
        /// </summary>
#if ODIN_INSPECTOR
        [Button("刷新图表")]
#endif
        public void Refresh()
        {
            // 优先进行数据处理
            for (int i = 0; i < Processors.Length; i++) Processors[i].Process();

            // 逐个渲染
            for (int i = 0; i < Renders.Length; i++)
            {
                Renders[i].Render();
            }
        }

        /// <summary>
        ///  比较两个渲染器的优先级
        /// </summary>
        private static int Comparison(IChartRender a, IChartRender b)
        {
            return a.Priority.CompareTo(b.Priority);
        }

        protected override void OnValidate()
        {
            foreach (var each in editorPoint)
                AddPoint(each, false);
            _renders = null;
            _sortedProcessors = null;
            base.OnValidate();
        }
    }
}